/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 string_table.h

	$Header: /resource_editor/string_table.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined(STRING_TABLE_H_INCLUDED)
#define STRING_TABLE_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#pragma warning( disable: 4786 ) // Disable the ever so helpful "identifier was truncated to '255' characters" warning

#include <iterator>
#include <string>
#include <vector>
#include <utility>

#include "table.h"

class t_string_table_const_iterator;

// -------------------------------------------------------------------------------
// t_string_table class - a string map class
// -------------------------------------------------------------------------------
class t_string_table
{
private:
	// Types
	typedef std::vector< t_table::size_type > t_index_vector;

public:
	// Types
	typedef t_string_table_const_iterator			const_iterator;
	typedef t_index_vector::size_type				size_type;
	typedef std::pair< std::string, std::string >	value_type;

	// Constructors
	t_string_table() {}
	t_string_table( t_string_table const & other );
	t_string_table( t_string_table const & other, std::string const & key_suffix );

	// Member functions
	const_iterator		begin() const;
	const_iterator		end() const;
	const_iterator		find( std::string const & key ) const;
	std::string			get_string( std::string const& key ) const;
	t_table&			get_table();
	t_table const&		get_table() const;
	void				import( t_table const& table );   // import data from a unsorted table.
	void				insert( std::string const& key, std::string const& value );
	bool				read( std::streambuf& buffer );
	size_type			size() const;
	bool				write( std::streambuf& buffer ) const;

	// Operator
	t_string_table &	operator=( t_string_table const & other );
	value_type const	operator[]( size_type index ) const;

private:
	// Static member functions
	static t_index_vector	create_index_vector( t_table const & table );

	// Data members
	t_table			m_table;
	t_index_vector	m_index_vector;

	// Member functions
	t_index_vector::const_iterator	do_find( std::string const & key ) const;

	friend class t_string_table_const_iterator;
};

inline t_table& t_string_table::get_table()
{
	return m_table;
}

inline t_table const& t_string_table::get_table() const
{
	return m_table;
}

inline t_string_table::size_type t_string_table::size() const
{
	return m_index_vector.size();
}

inline bool read( std::streambuf& buffer, t_string_table& table )
{
	return table.read( buffer );
}

template <>
struct t_resource_traits<t_string_table>
{
	static char const prefix[];
	static char const extension[];
};

// -------------------------------------------------------------------------------
// t_string_table_const_iterator class
// -------------------------------------------------------------------------------

class t_string_table_const_iterator :
	public	std::iterator<
				std::random_access_iterator_tag,
				std::pair< std::string, std::string > >
{
public:
	// Types
	class t_arrow_return
	{
	public:
		// Constructor
		t_arrow_return( value_type const & value ) : m_value( value ) {}

		// Operator
		value_type const * operator->() const { return &m_value; }

	private:
		// Data members
		value_type	m_value;
	};

	// Constructors
	t_string_table_const_iterator() {}
	t_string_table_const_iterator(
		t_string_table const &	string_table,
		size_t					index );

	// Operators
	t_string_table_const_iterator &	operator+=( distance_type dist );
	t_string_table_const_iterator &	operator-=( distance_type dist );
	t_string_table_const_iterator &	operator++();
	t_string_table_const_iterator	operator++( int );
	t_string_table_const_iterator &	operator--();
	t_string_table_const_iterator	operator--( int );
	value_type const				operator*() const;
	t_arrow_return const			operator->() const;
	value_type const				operator[]( distance_type dist ) const;

private:
	// Data members
	t_string_table const *	m_string_table_ptr;
	size_t					m_index;

	friend bool				operator==(
								t_string_table_const_iterator const &	left,
								t_string_table_const_iterator const &	right );
	friend bool				operator<(
								t_string_table_const_iterator const &	left,
								t_string_table_const_iterator const &	right );
	friend distance_type	operator-(
								t_string_table_const_iterator const &	left,
								t_string_table_const_iterator const &	right );
};

inline t_string_table_const_iterator::t_string_table_const_iterator(
	t_string_table const &	string_table,
	size_t					index )
	:	m_string_table_ptr( &string_table ),
		m_index( index )
{
}

inline t_string_table_const_iterator &
t_string_table_const_iterator::operator+=( distance_type dist )
{
	m_index += dist;
	return *this;
}

inline t_string_table_const_iterator &
t_string_table_const_iterator::operator-=( distance_type dist )
{
	m_index -= dist;
	return *this;
}

inline t_string_table_const_iterator &
t_string_table_const_iterator::operator++()
{
	++m_index;
	return *this;
}

inline t_string_table_const_iterator
t_string_table_const_iterator::operator++( int )
{
	t_string_table_const_iterator result( *this );
	++m_index;
	return result;
}

inline t_string_table_const_iterator &
t_string_table_const_iterator::operator--()
{
	--m_index;
	return *this;
}

inline t_string_table_const_iterator
t_string_table_const_iterator::operator--( int )
{
	t_string_table_const_iterator result( *this );
	--m_index;
	return result;
}

inline t_string_table_const_iterator::value_type const
t_string_table_const_iterator::operator*() const
{
	t_string_vector const & row =
		m_string_table_ptr->m_table[ m_string_table_ptr->m_index_vector[ m_index ] ];
	return value_type( row[ 0 ], row[ 1 ] );
}

inline t_string_table_const_iterator::t_arrow_return const
t_string_table_const_iterator::operator->() const
{
	return operator*();
}

inline t_string_table_const_iterator::value_type const
t_string_table_const_iterator::operator[]( distance_type dist ) const
{
	t_string_table_const_iterator temp( *this );
	temp += dist;
	return *temp;
}

inline bool operator==(
	t_string_table_const_iterator const &	left,
	t_string_table_const_iterator const &	right )
{
	return		left.m_string_table_ptr == right.m_string_table_ptr
			&&	left.m_index == right.m_index;
}

inline bool operator!=(
	t_string_table_const_iterator const &	left,
	t_string_table_const_iterator const &	right )
{
	return !( left == right );
}

inline bool operator<(
	t_string_table_const_iterator const &	left,
	t_string_table_const_iterator const &	right )
{
	return left.m_index < right.m_index;
}

inline bool operator>(
	t_string_table_const_iterator const &	left,
	t_string_table_const_iterator const &	right )
{
	return right < left;
}

inline bool operator<=(
	t_string_table_const_iterator const &	left,
	t_string_table_const_iterator const &	right )
{
	return !( left > right );
}

inline bool operator>=(
	t_string_table_const_iterator const &	left,
	t_string_table_const_iterator const &	right )
{
	return !( left < right );
}

inline t_string_table_const_iterator operator+(
	t_string_table_const_iterator const &			left,
	t_string_table_const_iterator::distance_type	right )
{
	t_string_table_const_iterator result( left );
	result += right;
	return result;
}

inline t_string_table_const_iterator operator+(
	t_string_table_const_iterator::distance_type	left,
	t_string_table_const_iterator const &			right )
{
	return right + left;
}

inline t_string_table_const_iterator operator-(
	t_string_table_const_iterator const &			left,
	t_string_table_const_iterator::distance_type	right )
{
	t_string_table_const_iterator result( left );
	result -= right;
	return result;
}

inline t_string_table_const_iterator::distance_type operator-(
	t_string_table_const_iterator const &	left,
	t_string_table_const_iterator const &	right )
{
	return left.m_index - right.m_index;
}

// -------------------------------------------------------------------------------
// Additional t_string_table members
// -------------------------------------------------------------------------------

inline t_string_table::const_iterator t_string_table::begin() const
{
	return const_iterator( *this, 0 );
}

inline t_string_table::const_iterator t_string_table::end() const
{
	return const_iterator( *this, m_index_vector.size() );
}

inline t_string_table::const_iterator t_string_table::find(
	std::string const & key ) const
{
	return const_iterator( *this, do_find( key ) - m_index_vector.begin() );
}

inline std::string t_string_table::get_string( std::string const & key ) const
{
	t_index_vector::const_iterator index_iter = do_find( key );
	return index_iter != m_index_vector.end() ? m_table[ *index_iter ][ 1 ] : std::string();
}

inline t_string_table::value_type const
t_string_table::operator[]( size_type index ) const
{
	return *( begin() + index );
}

#endif // STRING_TABLE_H_INCLUDED
